feat(engine): honor W3C tracestate on inbound HTTP and surface distributed traces#1921
feat(engine): honor W3C tracestate on inbound HTTP and surface distributed traces#1921guibeira wants to merge 7 commits into
Conversation
…1769) Co-authored-by: Guilherme Beira <guilherme.vieira.beira@gmail.com>
Follow-up to the merged traceparent propagation PR. - Add extract_context_with_state(traceparent, tracestate, baggage); the W3C TraceContextPropagator only populates a SpanContext's TraceState when both traceparent and tracestate are present, so a bare traceparent silently dropped any incoming tracestate. extract_context now delegates with None. - SpanExt::with_parent_headers takes tracestate as the W3C companion header; the HTTP boundary (views.rs) reads the tracestate header and forwards it. Non-HTTP callers (queue adapters, invocation) pass None — the engine protocol does not carry tracestate across hops. - Treat the baggage header as sensitive in sanitize_headers_for_logging so user/session metadata is not emitted to logs. - Tests for tracestate extraction, empty-state default, and baggage redaction.
StoredSpan dropped the span's own W3C tracestate (only links carried it), so the inbound tracestate honored on the HTTP server span was invisible to engine::traces::list and the console. Add a top-level trace_state field populated from the span context (omitted when empty), making trace-context propagation verifiable end-to-end. OTLP-ingested spans pass None for now. Verified e2e: curl with traceparent+tracestate -> HTTP span carries the trace id and tracestate, propagated to the worker span in the same trace.
list_traces treated a span as a trace root only when parent_span_id was None. A trace entering iii from an external caller via an incoming traceparent has a server span whose parent is the remote caller's span — never stored here — so the whole trace was hidden from the root-only listing (and thus the console). Treat a span as a root when its parent is absent from the store, mirroring build_span_tree's dangling-parent handling. Verified e2e: a curl carrying traceparent+tracestate now appears in the default (root-only, non-internal) trace list.
build_span_tree only rooted spans with no parent, so the server span of a trace entering iii via an incoming traceparent (parent = remote caller, not stored) was orphaned into the children map and never emitted — the trace detail view showed "No span data available". Treat a span as a root when its parent is absent from the span set, matching the traces::list fix. Updated the orphan-child test to assert the corrected behavior. Verified e2e: traces::tree now returns the HTTP server span and its worker child for a propagated trace.
|
The latest updates on your projects. Learn more about Vercel for GitHub.
|
|
No actionable comments were generated in the recent review. 🎉 ℹ️ Recent review info⚙️ Run configurationConfiguration used: Repository UI Review profile: CHILL Plan: Pro Run ID: 📒 Files selected for processing (11)
📝 WalkthroughWalkthroughAdds W3C ChangesW3C Tracestate Propagation and Dangling-Parent Root Fix
Estimated code review effort🎯 3 (Moderate) | ⏱️ ~25 minutes Possibly related PRs
Suggested reviewers
🚥 Pre-merge checks | ✅ 5✅ Passed checks (5 passed)
✨ Finishing Touches📝 Generate docstrings
🧪 Generate unit tests (beta)
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
What
Completes W3C trace-context propagation for inbound HTTP requests and makes the
resulting distributed traces visible in the console.
Builds on #1769 (propagate
traceparent) with:tracestateon inbound HTTP —traceparent's W3C companion header.extract_contextonly seededtraceparentinto the propagation carrier, soTraceContextPropagatorsilently dropped any incomingtracestate. The HTTPboundary (
rest_api/views.rs) now readstracestateand forwards it throughSpanExt::with_parent_headers. Non-HTTP callers passNone(the engineprotocol does not carry
tracestateacross hops — boundary-only by design).baggagein header logs — baggage often carries user/sessionmetadata; it's now treated as sensitive in
sanitize_headers_for_logging.tracestatein the traces API —StoredSpandropped thespan's own
tracestate(only links carried it), so the honored value wasinvisible to
engine::traces::listand the console.traces::listandtraces::tree— bothtreated a span as a trace root only when
parent_span_idwasNone. A traceentering iii via an incoming
traceparenthas a server span whose parent isthe remote caller's span (never stored here), so the whole trace was hidden
from the list and the detail view rendered "No span data available". Both now
treat a span as a root when its parent is absent from the store.
Why
Without
tracestate, iii silently drops vendor trace state on the server span,breaking distributed traces that rely on it. The observability gaps meant a
correctly-propagated trace was invisible in the console, so the feature was
effectively unusable for its main purpose (end-to-end observability of requests
entering iii from an upstream service).
Notes
curlcarryingtraceparent+tracestate+baggageproduces an engine HTTP span under the caller's trace id, carrying the
tracestate, propagated to the worker span in the same trace, and visible inthe console trace list and detail tree.
redaction,
StoredSpantracestate, and dangling-remote-parent roots in bothtraces::listandbuild_span_tree.tracestatepropagation (protocol +queue jobs + SDKs) is intentionally out of scope.
Summary by CodeRabbit
New Features
Bug Fixes